﻿#define _CRT_SECURE_NO_WARNINGS
// demon12-string-2.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。

//string的迭代器Iterators：begin、end、rbegin、rend、cbegin 、cend、crbegin、crend 
//  begin: 将迭代器返回到开头的位置
//    end: 返回迭代器到'\0'的位置
// rbegin: 返回反向迭代器以反转开头
//   rand: 返回反向迭代器以反向结束
// cbegin: 将 const_iterator 返回到开头
//   cend: 将 const_iterator 返回到 end
//crbegin: 将 const_reverse_iterator 返回为反向开头
//  crend: 将 const_reverse_iterator 返回到反向端


//迭代器和反向迭代器的比较
/*
#include <iostream>
#include<string>
#include<vector>
#include<list>
using namespace std;

void Test_string()              //普通迭代器，可读可写
{
    //正向迭代器
    cout << "正向迭代器调用:" << endl;
    string st1("hello world!");
    string::iterator it_st1 = st1.begin();
    while (it_st1 != st1.end())
    {
        cout << *it_st1 << " ";
        ++it_st1;
    }
    cout << endl<<"调用范围for：\n";
    //范围for调用
    for (auto e : st1)
    {
        cout << e << " ";
    }
    cout << endl << endl;
}

void Test_const_string()       //const修饰的普通迭代器只读
{
    cout << "const修饰的正向迭代器调用:" << endl;
    const string st1("hello world!");
    string::const_iterator it_st1 = st1.cbegin();
    while (it_st1 != st1.cend())
    {
        cout << *it_st1 << " ";
        ++it_st1;
    }
    cout << endl << "调用范围for：\n";
    //范围for调用
    for (auto e : st1)
    {
        cout << e << " ";
    }
    cout << endl << endl;
}

void Test_string_reverse()
{
    cout<< "反向迭代器的调用:\n";
    //反向迭代器
    string st2("hello world!");
    string::reverse_iterator rit_st2 = st2.rbegin();
    while (rit_st2 != st2.rend())
    {
        cout << *rit_st2 << " ";
        ++rit_st2;
    }
    cout << endl << "调用范围for：\n";
    for (auto e : st2)
    {
        cout << e << " ";
    }
    cout << endl << endl;
}

void Test_const_string_reverse()
{
    cout << "const修饰的反向迭代器的调用:\n";
    //反向迭代器
    const string st2("hello world!");
    string::const_reverse_iterator rit_st2 = st2.crbegin();
    while (rit_st2 != st2.crend())
    {
        cout << *rit_st2 << " ";
        ++rit_st2;
    }
    cout << endl << "调用范围for：\n";
    for (auto e : st2)
    {
        cout << e << " ";
    }
    cout << endl << endl;
}

int main()
{
    //正向迭代器
    Test_string();
    Test_const_string();
    //逆序迭代器
    Test_string_reverse();
    Test_const_string_reverse();
    return 0;
}
*/

//string的容量Capacity: size、length、max_size、resize、capacity、reserve、clear、empty、shrink_to_fit 
//          size：返回字符串长度
//        length：返回字符串长度
//      max_size：返回字符串的最大大小
//        resize：调整字符串大小
//      capacity：返回已分配存储的大小
//       reserve：请求更改容量
//         clear：清除字符串
//         empty：测试 string 是否为空
// shrink_to_fit：收缩容量以适应

/*
#include<iostream>
#include<string>
using namespace std;

void Test_string_1()
{
    string st1("hello world!xxxxxxxxhahaxxxxxxxx!!!");                 
    cout << "st1 = " << st1 << endl;
    cout << "st1.size() = " << st1.size() << endl;                       //st1的字符长度
    cout <<"st1.length() = " << st1.length() << endl;                    //st1的字符长度
    cout << "st1.max_size() = " << st1.max_size() << endl;               //st1字符串的最大容纳大小
    cout << "st1.capacity() = " << st1.capacity() << endl;               //返回st1分配存储的大小

    st1.resize(40);
    cout << "st1.resize(40)= " << st1 << endl;     //n=40,n＞35,前35个字符是st1的全部字符，后续补充'\0'填满40个字符
    st1.resize(20);
    cout << "st1.resize(20)= " << st1 << endl;     //n=25,n<25,st1中的前25个字符
    st1.resize(10);
    cout << "st1.resize(10)= " << st1 << endl;
    st1.resize(20,'y');
    cout << "st1.resize(20)= " << st1 << endl << endl;
    //如果 n 小于当前字符串长度，则当前值将缩短为其前 n 个字符，并删除第 n个字符以外的字符
    //如果 n 大于当前字符串长度，则通过在末尾插入所需数量的字符来扩展当前内容，以达到 n 的大小。
    //如果指定了 c，则新元素将初始化为 c 的副本，否则，它们是值初始化字符（空字符）

    st1.clear();                                  //清空字符，空间不变，还是47
    cout << "清空字符串内容：\nst1.clear() = " << st1 << endl;
    cout << "st1.capacity() = " << st1.capacity() << endl<<endl;
    //清空字符后，就不要那么大的空间,进行容量收缩
    st1.shrink_to_fit();
    cout <<"收缩容量：\nst1 = " << st1 << endl;
    cout << "st1.capacity() = " << st1.capacity() << endl<<endl;

    st1 = "hello world!";
    cout << st1 << endl;
    cout << "st1.capacity() = " << st1.capacity() << endl;
    cout << "st1.size() = " << st1.size() << endl << endl;
    //更改容量,比当前capacity大才会扩容
    st1.reserve(10);
    cout << "修改容量：\nst1 = " << st1 << endl;
    cout << "st1.capacity() = " << st1.capacity() << endl;
    cout << "st1.size() = " << st1.size() << endl<<endl;

    st1.reserve(100);
    cout << "st1 = " << st1 << endl;
    cout << "st1.capacity() = " << st1.capacity() << endl;
    cout << "st1.size() = " << st1.size() << endl<<endl;

    // 查看扩容机制,vs下的扩容开始是2倍，然后是1.5倍扩容；而linux下是2倍扩容
    string st2("hello world!xxx");
    size_t sz = st2.capacity();
    cout <<"capacity change :" << sz << endl;
    cout << "making sz grow:" << endl;
    for (int i = 0; i < 100; i++)
    {
        st2.push_back('c');
        if (sz != st2.capacity())
        {
            sz = st2.capacity();
            cout << "capacity change:" << sz << endl;
        }
    }
}

int main()
{
    Test_string_1();
}
*/


//string的Element access: operator[]、at、back、front 
// operator[]: 获取字符串的字符
//         at: 获取字符串中的某个字符
//       back: 获取字符串的末尾字符
//      front: 获取字符串的首字符

/*
#include<iostream>
#include<string>
using namespace std;

void Test_string_Element_access()
{
    string st1("hello world!!!xxxx--xxxx!!!");
    cout <<"st1[6] = " << st1[6] << endl;                           //显示第六个位置的字符
    cout <<"st1.at(6) = " << st1.at(6) << endl;                     //显示第六个位置的字符
    //上述两行代码的区别：在于越界访问的检查不同，st1[]越界会报断言错误，st1.at()越界直接报错
 
    //显示错误信息
    try
    {
        //cout<<st1[35];                                             //报的断言错误
        //cout << st1.at(35);                                        //报错

    }
    catch (const exception &e)
    {
        cout << e.what() << endl;                                    //显示错误信息
    }

    cout <<"st1.front() = " << st1.front() << endl;                  //取字符串首位置的字符
    cout <<"st1.back() = " << st1.back() << endl;                    //取字符串末尾位置的字符
    cout << "st1 = " << st1<< endl;
}

int main()
{
    Test_string_Element_access();
    return 0;
}
*/

//string的修饰符Modifiers: operator+=、append、push_back、pop_back、assign、insert、erase、replace、swap
// operator+=：通过在字符串的当前值末尾附加其他字符来扩展字符串
//     append：通过在字符串的当前值末尾附加其他字符来扩展字符串：
//  push_back：将字符附加到字符串的末尾，将其长度增加 1。
//   pop_back：擦除字符串的最后一个字符，从而有效地将其长度减少 1。
//     assign: 为字符串分配一个新值，替换其当前内容。
//     insert：将其他字符插入字符串中 pos（或 p）指示的字符之前：
//      erase：擦除字符串的一部分，减少其长度：
//    replace：将字符串中从字符 pos 开始并跨越 len 字符的部分（或 [i1，i2） 之间范围内的字符串部分）替换为新内容：
//       swap：交换字符串值

/*
#include<iostream>
#include<string>
using namespace std;

void Test_string_Modifiers()
{
    //通常使用+=比较方便
    string st1("xxx-hello world!!!-xxx");                        
    cout << "初始st1 :   " << st1 << endl;                       
    st1 += "sdf";                                                //字符串末尾加字符串
    cout << "\nst1 += sdf :\n" << st1 << endl;
    st1 += 'a';                                                  //字符串末尾加一个字符
    cout << "\nst1 += a :\n" << st1 << endl<<endl;

    st1 = "xxx-hello world!!!-xxx";
    cout << "重新修正的st1 :   " << st1 << endl;             
    cout << "st1.append(-hello world) = " << st1.append("-hello world") << endl;   //字符串末尾加入字符串-hello world
    cout << "st1.append(10, 'y') = " << st1.append(10, 'y')<<endl;                 //字符串末尾添加10个字符y

    string st2("zz--apple--zz");
    st1.append(st2);                                            //st1字符串末尾附加st2字符串
    cout << "st1.append(st2) = " << st1 << endl;                //显示新的st1字符串
    cout << st1.append(st2.begin(), st2.end())<<endl<<endl;     //将st2的首字符到末尾字符的全部位置附加到st1的末尾
    
    cout << "st2 = " << st2 << endl;                            
    st2.push_back('a');                                         //字符串末尾加一个字符a，长度+1
    cout << "st2 = " <<st2<< endl;                                
    st2.pop_back();                                             //删除字符串末尾的第一个字符，长度-1
    cout << "st2 = " <<st2<<endl<<endl;

    //assign日常很少用
    string st3("hello world!!");
    cout <<"st3.assign(xxxxxx) = " << st3.assign("xxxxxx") << endl;   //把字符串xxxxxx替换当前字符串的内容                                          
    cout <<"st3.assign(3, 'u') = " << st3.assign(3, 'u') << endl;     //把3个字符u替换st3的字符串内容
    cout<<"st3.assign(ssfafggwef, 2, 6) = " << st3.assign("ssfafggwef", 2, 6) << endl;
    //从字符串的第2个位置取6个字符替换原来的字符
    string st4("hello");
    cout <<"st3.assign(st4) = " << st3.assign(st4) << endl;          //st4的字符串内容替换st3的字符串
    cout << "st3.assign(st4, 0) = " << st3.assign(st4, 1)<<endl<<endl;     //从st4的第一个字符位置往后的全部字符替换st3的字符串内容

    //insert的调用方式，一般情况不建议使用
    string str("to be question");
    string str1("the ");
    string str2("or not to be");
    string::iterator it_str;
    cout<<"st4.insert(2,ssdsdaf) = " << st4.insert(2, "ssdsdaf") << endl;         //将其他字符串插入str4字符串中的第二个位置字符之前
    cout<<str.insert(6, str1) << endl;                                            //将str1字符串从str的第六个字符前插入
    cout << str.insert(6, str2, 3, 4) << endl;    //将str2字符串的第3个位置的字符开始往后的4个字符插入到str字符串的第六个字符位置前 
    cout << str.insert(10, "that is cool", 8) << endl;    //字符串"that is cool"的前8个字符插入到str字符串的第10个字符位置前 
    cout << str.insert(10, "to be ") << endl;             //字符串"to be "从str字符串的第10个字符位置前插入
    cout << str.insert(15, 1, ':') << endl;               // 字符':'的一个字符，从str字符串的第15个字符位置前插入
    it_str = str.insert(str.begin() + 5, ',');            // str字符串的首字符+5个位置处，插入字符 ','
    cout << str << endl;
    str.insert(str.end(), 3, '.');                        // str字符串的末尾字符处插入3个字符'.'
    cout << str << endl<<endl;
  
    //erase的调用方式，一般情况不建议使用
    string str5("hello world!!!");
    cout<<str5.erase(5, 3)<<endl;                        //将字符串第5个字符处开始往后删除3个字符（包括第5个字符），然后合并
    string::iterator it_str5;
    str5.erase(str5.begin()+3);                          //删除str5字符串首字符+3的位置处的字符，注意数字是下标
    cout << str5 << endl;
    it_str5 = str5.erase(str5.begin() + 3);              //删除str5字符串首字符+3位置处的字符，然后赋值给it_str5
    cout << str5 << endl;
    str5.erase(str5.begin() + 1, str5.end() - 6);        //删除str5字符串首字符+1处和末尾字符往回数的第六个字符
    cout << str5 << endl<<endl;

    //insert / erase / replace     // 能少用就要少用，因为基本都要挪动数据，效率不高
        
    //replace的调用方式
    string st_1("hello world and hello bit!!!");
    string st_2("xyzijq C");
    cout<<st_1.replace(3,4,st_2)<<endl;               //st_1字符串的第3个位置处的字符往后4个字符被st_2字符串替换             
    cout << st_1.replace(5, 1, "20%") << endl;        //st_1字符串的第5个字符位置往后的1个字符被替换成字符串"20%"
    //可以配合find使用
    size_t pos = st_1.find(" ");                      //找到st_1字符串的空格,赋值给pos
    while (pos!=string::npos)                         //如果pos不是字符串末尾，进入循环
    {
        st_1.replace(pos, 1, "20%");                  //将st_1字符串的pos位置处，放入1个字符串"20%"将原来的空格替换掉
        pos = st_1.find(' ');                         //再找下一个空格位置
    }
    cout <<"st_1 = " << st_1 << endl << endl;         //显示结果

    //swap的调用方式
    st_1.swap(st_2);
    cout <<"st_1 = " << st_1 << endl;
    cout << "st_2 = " << st_2 << endl;

}

int main()
{
    Test_string_Modifiers();    
    return 0;
}
*/


//字符串操作：String operations:
// c_str、data、get_allocator、copy、find、rfind、find_first_of、find_last_of、find_first_not_of、find_last_not_of、substr、compare
// c_str：获得C语言类型的字符串
// data：获得字符串数据
// get_allocator：返回与字符串相关的分配器对象的副本。即在内存池里找与字符串相同的副本
// copy：从字符串中复制字符序列
// find：查找字符串中的内容
// rfind：查找字符串中最后出现的内容
// find_first_of：搜索字符串中与其参数中指定的任何字符相匹配的第一个字符
// find_last_of：搜索字符串中与参数中指定的任何字符匹配的最后一个字符。
// find_first_not_of：搜索字符串中第一个与其参数中指定的字符不匹配的字符
// find_last_not_of：搜索字符串中与参数中指定的字符不匹配的最后一个字符。
// substr：返回一个新构造的字符串对象，其值初始化为该对象子串的副本。
// compare：将字符串对象（或子串）的值与参数指定的字符序列进行比较。

/*
#include<iostream>
#include<string>
using namespace std;

void Test_string_operations_c_str()
{
    //c_str的调用
    string str_1("hello world!!!");
    char* str_p = new char[str_1.length()+1];           //开辟str_1字符串长度+1大小的空间
    cout << "str_1 = " << str_1 << endl;                //显示str_1字符串
    cout << "&str_1 = " << &str_1 << endl;              //显示str_1字符串
    cout << "*str_p = " << (void*)str_p << endl;        //显示str_p的地址
    cout << "str_p = " << *str_p << endl;               //显示str_p的字符串，此时为空
    strcpy(str_p, str_1.c_str());                       //把对象str_1以C语言字符串拷贝给str_p,调用c_str()把对象内容底层的字符数组以C字符串的形式返回
    char* p = strtok(str_p," ");                        //从符号空格处进行截断，strtok的效率不高，实践尽量不使用
    while (p != 0)
    {
        cout << "p = " << p << endl;                    //显示p指向字符串的值
        p = strtok(NULL," ");                           //从空格处截断并置为空，然后赋值给p
    }
    cout << endl;
    delete[]str_p;                                      //释放内存
}

void Test_string_operations_data()
{
    string str("Test string");
    char* str_p = new char[12] {"Test string"};
    if (str.length() == strlen(str_p))                      //判断str的字符串长度和str_p的字符串长度是否相同，相同则显示
    {
        cout << "str and cstr have the same length.\n";     //memcmp
        if (memcmp(str_p, str.data(), str.length()) == 0)   //判断str_p和str两个内存块的前12个字符对应ASCII值的大小，相同则返回0
        {
            cout<< "str and cstr have the same content.\n";
        }
    }
    cout << endl;
    delete[]str_p;
}

void Test_string_operations_get_allocator()
{
    //.....内存池以后写
}

void Test_string_operations_copy()
{
    string str("Test string...");
    char buffer[20];
    size_t length = str.copy(buffer, 6, 5);            //从字符串str中复制第5字符位置往后的6个字符序列，赋值给buffer
    buffer[length] = '\0';                             //将字符串buffer的第6个字符处赋值'\0'
    cout << "buffer contains ：" << buffer << endl;
    cout << endl;
}

void Test_string_operations_find() //find 在字符串中搜索由其参数指定的序列的第一个匹配项
{
    string str_1("There are two needles in this haystack with needles.");
    string str_2("needle");
    size_t found = str_1.find(str_2);       //str_2字符序列与str_1字符串中的第几个字符开始相匹配，str_1的第14个字符位置与str_2匹配

    if (found != string::npos)              
        cout << "first 'needle' found at: " << found << '\n';       //found=14
    
    found = str_1.find("needles are small", found+1, 6);           //found=44，字符串"needles are small"的前6给字符与str_1的find+1位置(即第15个字符往后)往后找相匹配
    if (found != std::string::npos)
        cout << "second 'needle' found at: " << found << '\n';  

    found = str_1.find("haystack");                                 //fuond=30
    if (found != std::string::npos)
        cout << "'haystack' also found at: " << found << '\n';

    found = str_1.find('.');                                        //found=51
    if (found != std::string::npos)
        cout << "Period found at: " << found << '\n';

    // let's replace the first needle:
    cout << "str_2.length() = " << str_2.length() << endl;
    str_1.replace(str_1.find(str_2), str_2.length(), "preposition"); //在str_1找到与str_2相匹配的6个字符，然后与字符串"preposition"进行替换
    cout << str_1 << '\n' << endl;
}

void test_string()
{
    string str("file.cpp.tar.zip");
    size_t pos = str.find(".");            //找到字符'.'往后的全部字符赋值给pos  
    if (pos != string::npos)
    {
        string suffix = str.substr(pos);   //substr()取字符串的一个字串，从pos位置开始直接取到结尾字符
        cout <<"suffix = "<< suffix << endl;
    }
    else
    {
        cout << "没有后缀" << endl;
    }

    size_t pos_1 = str.rfind(".");
    if (pos_1 != string::npos)
    {
        string suffix_1 = str.substr(pos_1);   //substr()取字符串的一个字串，从pos_1位置开始从字符串末尾往前找字符'.'
        cout << "suffix_1 = " << suffix_1 << endl;
    }
    else
    {
        cout << "没有后缀" << endl;
    }
                 //协议+域名+资源名(uri)
    string url1("https://legacy.cplusplus.com/reference/string/string/substr/");
    string url2("http://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=650/");
    //需要找到协议
    string protocol, domain, uri;                         //协议protocol, 域名domain,网址/资源名uri;
    size_t i_1 = url1.find(':');                          //找https则需要找到字符':'即可
    if (i_1 != string::npos)
    {                                                     //i_1-0实际就是i_1字符串从从首字符位置到'\0'的位置，即https
        protocol = url1.substr(0, i_1 - 0);               //从首字符位置开始往后找到i_1 - 0位置处的字符
        cout <<"protocol = " << protocol << endl;         //protocol = https
    }

    size_t i_2 = url1.find("/", i_1 + 3);                 //i_1+3的位置开始找字符'/'
    if (i_2 != string::npos)
    {
        domain = url1.substr(i_1 + 3, i_2 - (i_1 + 3));   //从i_1+3的字符位置开始找，到i_2-(i_1-3)的位置的字符，这个区间构成的子字符串
        cout << "domain = " << domain << endl;
    }
    uri = url1.substr(i_2 + 1);                           //从i_2+1的字符位置开始往后找，直到找到字符串末尾的全部字符构成一个子字符串
    cout << "uri = " << uri << endl;

    size_t i_3 = url2.find("baidu");
    cout << "i_3 = " << i_3 << endl << endl;
}

void Test_string_operations_find_first_of()             //在字符串中搜索与其参数中指定的任何字符匹配的第一个字符
{
    string str("Please, replace the vowels in this sentence by asterisks.");
    cout << "str = " << str << endl;
    size_t found = str.find_first_of("aeiou");          //找到指定的字符位置
    while (found != string::npos)
    {
        str[found] = '*';
        found = str.find_first_of("aeiou", found + 1);
    }
    cout << "str = " << str << endl<<endl;
}

void Test_string_operations_find_first_not_of()
{
    string str("Please, replace the vowels in this sentence by asterisks.");
    cout << "str = " << str << endl;
    size_t found = str.find_first_not_of("aeiou");
    while (found != string::npos)
    {
        str[found] = '*';
        found = str.find_first_not_of("aeiou", found + 1);
    }
    cout << "str = " << str << endl<<endl;
}

void Test_string_operations_find_last_of()
{
    string str("Please, replace the vowels in this sentence by asterisks.");
    cout << "str = " << str << endl;
    size_t found = str.find_last_of("aeiou");
    while (found != string::npos)
    {
        str[found] = '*';
        found = str.find_last_of("aeiou", found + 1);
    }
    cout << "str = " << str << endl << endl;
}

void Test_string_operations_find_last_not_of()
{
    string str("Please, erase trailing white-spaces   \n");
    string whitespaces(" \t\f\v\n\r");
    size_t found = str.find_last_not_of(whitespaces);
    if (found != std::string::npos)
        str.erase(found + 1);
    else
        str.clear();            // str is all whitespace
    cout << '[' << str << "]\n";
}

int main()
{
    Test_string_operations_c_str();
    Test_string_operations_data();
    Test_string_operations_get_allocator();
    Test_string_operations_copy();
    Test_string_operations_find();
    test_string();
    Test_string_operations_find_first_of();
    Test_string_operations_find_first_not_of();
    Test_string_operations_find_last_of();
    Test_string_operations_find_last_not_of();
    return 0;
}
*/


/*
#include<iostream>
#include<string>
using namespace std;

void Test_to_string()                          //其他类型转换成string类型
{
    int i = 1234;
    double j = 11.234;

    string st_1 = to_string(i);
    cout <<"st_1 = " << st_1 << endl;
    string st_2 = to_string(j);
    cout << "st_2 = " << st_2 << endl;
}

void Test_string()                            //
{
    char buff[] = "吃饭";
    cout << "sizeof(buff) = " <<sizeof(buff)<< endl;
    buff[1]--;
    cout << "buff = " << buff << endl;
    buff[3]--;
    cout << "buff = " << buff << endl;
}
int main()
{
    Test_to_string();
    Test_string();
    return 0;
}
*/